﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using FortuneUniverse.Fortune.Dyson;
using FortuneUniverse.Fortune.Util;

namespace FortuneUniverse
{
    public static class FortuneUniverseGen
    {
        public static Dictionary<string, object> 结果解析(GalaxyData galaxyData)
        {
            if (galaxyData != null) return 解析星系(galaxyData);
            Console.Out.WriteLine("galaxyData为空");
            return null;
        }

        private static Dictionary<string, object> 解析星系(GalaxyData galaxyData)
        {
            Dictionary<string, object> galaxy = new Dictionary<string, object>();
            // 拿到基础数据
            // ret["seed"] = galaxy.seed;
            // ret["starCount"] = galaxy.starCount;
            // ret["birthPlanetId"] = galaxy.birthPlanetId;
            // ret["habitableCount"] = galaxy.habitableCount;
            List<Dictionary<string, object>> stars = new List<Dictionary<string, object>>();
            galaxy["stars"] = stars;
            // 出生行星id
            galaxy["birthPlanetId"] = galaxyData.birthPlanetId;
            // 多线程处理恒星数据
            ParallelLoopResult starProcess = Parallel.For(0, galaxyData.stars.Length, startIndex =>
            {
                Dictionary<string, object> star = 解析主星(galaxyData.stars[startIndex], galaxyData);
                lock (stars)
                {
                    stars.Add(star);
                }
            });
            // 恒星没处理完，则等1s再次查询
            while (!starProcess.IsCompleted)
            {
                Thread.Sleep(1000);
            }

            return galaxy;
        }

        private static Dictionary<string, object> 解析主星(StarData starData, GalaxyData galaxyData)
        {
            // 先处理非数组数据
            Dictionary<string, object> star = new Dictionary<string, object>();
            // star["seed"] = starData.seed;
            // 和初始星的距离（光年）
            star["distance"] = DataSerializer.genDistance(starData, galaxyData.stars[0]);
            // star["index"] = starData.index;
            // id为1的
            // if (starData.id == galaxyData.birthStarId)
            // {
            //     // 标志初始化 出生星系id必为1
            //     star["birth"] = true;
            // }
            star["id"] = starData.id;
            star["name"] = starData.name;
            // 恒星类型：主星、巨星、白矮星、中子星、黑洞
            // star["type"] = starData.type;
            // 光谱，根据该字段判断是那种巨星，只在type为1生效
            // star["spectr"] = starData.spectr;
            star["type"] = DataSerializer.genStarType(starData.spectr, starData.type);
            // 光度 out byte
            // star["luminosity"] = (short) (starData.luminosity * 10);
            star["dysonLumino"] = (short) (starData.dysonLumino * 10);
            star["planetCount"] = starData.PlanetCount;
            // 星球数量
            // star["planetCount"] = starData.planetCount;
            // star["level"] = starData.level;
            // 资源系数 byte
            // star["resourceCoef"] = (byte)starData.resourceCoef * 100;
            
            // 矿脉信息
            Dictionary<string,bool> veins = new Dictionary<string, bool>();
            star["veins"] = veins;
            
            // 特性信息
            Dictionary<string, bool> singularities = new Dictionary<string, bool>();
            star["singularities"] = singularities;
            
            // 星球主题信息
            Dictionary<string, bool> themes = new Dictionary<string, bool>();
            star["themes"] = themes;
            
            // 星球类型信息
            // Dictionary<string, bool> planetTypes = new Dictionary<string, bool>();
            // star["planetTypes"] = planetTypes;

            int dysonContain = 0;
            
            foreach (PlanetData planetData in starData.planets)
            {
                PlanetAlgorithm planetAlgorithm = PlanetModelingManager.Algorithm(planetData);
                planetAlgorithm.GenerateVeins(starData, galaxyData);

                if (starData.dysonRadius * 2 > planetData.sunDistance)
                {
                    dysonContain++;
                }
                
                saveVein(planetData.veinSpotsSketch, veins);
                saveSingularity(planetData.singularity, singularities);
                saveTheme(planetData.theme, themes);
                // savePlanetType(planetData.type, planetTypes);
            }
            star["dysonContain"] = dysonContain;

            return star;
        }

        private static void savePlanetType(EPlanetType type, IDictionary<string, bool> dict)
        {
            string insertKey = null;
            switch (type)
            {
                case EPlanetType.Vocano:
                    insertKey = "vocano";
                    break;
                case EPlanetType.Ocean:
                    insertKey = "ocean";
                    break;
                case EPlanetType.Desert:
                    insertKey = "desert";
                    break;
                case EPlanetType.Ice:
                    insertKey = "ice";
                    break;
                case EPlanetType.Gas:
                    insertKey = "gas";
                    break;
                case EPlanetType.None:
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
            
            if (string.IsNullOrWhiteSpace(insertKey))
            {
                return;
            }

            if (dict.ContainsKey(insertKey))
            {
                return;
            }

            dict[insertKey] = true;
        }
        
        private static void saveTheme(int theme, IDictionary<string, bool> dict)
        {
            string insertKey = null;
            switch (theme)
            {
                case 1:
                    insertKey = "ocean1";
                    break;
                case 2:
                    insertKey = "gas1";
                    break;
                case 3:
                    insertKey = "gas2";
                    break;
                case 4:
                    insertKey = "gas3";
                    break;
                case 5:
                    insertKey = "gas4";
                    break;
                case 6:
                    insertKey = "desert1";
                    break;
                case 7:
                    insertKey = "desert2";
                    break;
                case 8:
                    insertKey = "ocean2";
                    break;
                case 9:
                    insertKey = "lava1";
                    break;
                case 10:
                    insertKey = "ice1";
                    break;
                case 11:
                    insertKey = "desert3";
                    break;
                case 12:
                    insertKey = "desert4";
                    break;
                case 13:
                    insertKey = "volcanic1";
                    break;
                case 14:
                    insertKey = "ocean3";
                    break;
                case 15:
                    insertKey = "ocean4";
                    break;
                case 16:
                    insertKey = "ocean5";
                    break;
                case 17:
                    insertKey = "desert5";
                    break;
                case 18:
                    insertKey = "ocean6";
                    break;
                case 19:
                    insertKey = "desert6";
                    break;
                case 20:
                    insertKey = "desert7";
                    break;
            }
            if (string.IsNullOrWhiteSpace(insertKey))
            {
                return;
            }

            if (dict.ContainsKey(insertKey))
            {
                return;
            }

            dict[insertKey] = true;
        }

        private static void saveSingularity(EPlanetSingularity singularity, IDictionary<string, bool> dict)
        {
            List<EPlanetSingularity> singularities = new List<EPlanetSingularity>();
            if ((singularity & EPlanetSingularity.TidalLocked) != EPlanetSingularity.None)
                singularities.Add(EPlanetSingularity.TidalLocked);
            if ((singularity & EPlanetSingularity.TidalLocked2) != EPlanetSingularity.None)
                singularities.Add(EPlanetSingularity.TidalLocked2);
            if ((singularity & EPlanetSingularity.TidalLocked4) != EPlanetSingularity.None)
                singularities.Add(EPlanetSingularity.TidalLocked4);
            if ((singularity & EPlanetSingularity.LaySide) != EPlanetSingularity.None)
                singularities.Add(EPlanetSingularity.LaySide);
            if ((singularity & EPlanetSingularity.ClockwiseRotate) != EPlanetSingularity.None)
                singularities.Add(EPlanetSingularity.ClockwiseRotate);
            if ((singularity & EPlanetSingularity.MultipleSatellites) != EPlanetSingularity.None)
                singularities.Add(EPlanetSingularity.MultipleSatellites);
            if (singularities.Count < 1)
            {
                return;
            }
            
            foreach (EPlanetSingularity ePlanetSingularity in singularities)
            {
                string insertKey = null;
                switch (ePlanetSingularity)
                {
                    case EPlanetSingularity.TidalLocked:
                        insertKey = "tidalLocked";
                        break;
                    case EPlanetSingularity.TidalLocked2:
                        insertKey = "TidalLocked2";
                        break;
                    case EPlanetSingularity.TidalLocked4:
                        insertKey = "TidalLocked4";
                        break;
                    case EPlanetSingularity.LaySide:
                        insertKey = "LaySide";
                        break;
                    case EPlanetSingularity.ClockwiseRotate:
                        insertKey = "ClockwiseRotate";
                        break;
                    case EPlanetSingularity.MultipleSatellites:
                        insertKey = "MultipleSatellites";
                        break;
                    case EPlanetSingularity.None:
                        break;
                    default:
                        Console.Out.WriteLine("\n\n\n");
                        Console.Out.WriteLine(singularity);
                        throw new ArgumentOutOfRangeException(nameof(singularity), singularity, null);
                }

                if (string.IsNullOrWhiteSpace(insertKey))
                {
                    return;
                }

                if (dict.ContainsKey(insertKey))
                {
                    return;
                }

                dict[insertKey] = true;
            }
        }

        private static void saveVein(IReadOnlyList<int> veins, IDictionary<string, bool> dict)
        {
            for (int i = 1; i < veins.Count; i++)
            {
                string veinName = DataSerializer.mapVeinName(i);
                // 资源数量不为0且不存在该key则添加可以
                if (veins[i] > 0 && !dict.ContainsKey(veinName))
                {
                    dict[veinName] = true;
                }
            }
        }
    }
}